
/**
 * -------------------------------------------------------------
 * 对bootstrap的封装, 解决panel模块化的问题
 * 尽量避免全局变量污染, 避免全局selector的引用
 * -------------------------------------------------------------
 * @author 赵卉华
 * date: 2016-09-22
 * -------------------------------------------------------------
 */
+function($){
	var xui = window.xui = { serial:0, original:{} };

	var VARS = /(['"]?)\b(_*\w+)\b(["']?\s*:\s*)([_\$a-z][\$\.\w]+)/gim;
	var BASE = /^(true|false|function|this|window|[\.\d]+)$/;
	var DELAY = "x-delay";

	var toOptions = function(item) {
		if (typeof(item) == "string") {
			// 简写转换为完整格式, 'Gender' -- {'Gender':'Gender'}
			var temp = {};
			temp[item] = item;
			return temp;
		} else {
			return item;
		}
	};

	$.fn.xui = function(variables) {
		if (variables == "load") {
			var args = Array.prototype.slice.call(arguments, 1);
			return this.each(function() {
				loadPage.apply(this, args);
			});
		}
	};

	/**
	options : {
		hash : string, // 用于判断是否已加载和hash导航, 必填
		space: string, // 页面空间, 非必填,通过href或hash计算
		xref : string, // 指向另一个页面, 与目标页面只有hash和initial参数不同
		href : string, // 打开哪个页面, 非必填,通过hash计算
		menu : boolean, // 是否与左侧菜单关联, 默认为true
		homepage : boolean, // 首页的hash导航不同, 默认为false
	}
	*/
	var loadPage = function(options) {
		if (!$.isPlainObject(options)) {
			options = { hash:options };
		} else if (!options.hash) {
			$.log.debug("Cann't load the page, options.hash is null.");
			return;
		}

		var me = $(this);

		// /system/#/auth/personnel/account/ 标准的#方案
		// /system/auth/personnel/account/ 跳转页面方案
		// /system/auth/personnel/account/ --> hash:'../dept/' 局部刷新方案
		var hash = (options.xref || options.hash);
		var path;
		if (hash.startsWith('#') || hash.charAt(0) == '/') {
			hash = hash.replace(/^#/, "");
			path = hashToPath(hash);
		} else { // 相对路径
			var base = DEF.getBaseUrl("");
			var curr = location.pathname.substring(base.length - 1);
			var newer = curr + (curr.endsWith("/") ? "" : "/../") + hash;
			var href = formatPath(newer);
			var m = /^\/([\-\.\w]+)\/((?:[\-\.\w]+\/)+)$/.exec(href);
			var view = m[2].replace(/^\/|\/$/g, "");
			hash = "/" + view + "/";
			options.hash = hash;
			options.href = href;
			path = { href:href, module:m[1], view:view };
		}

		// 如果没有view, 根据约定规则计算view
		if (!options.view) {
			options.view = path.view;
		}
		if (!options.space) {
			options.space = viewToSpace(options.view);
		}

		// 如果没有href, 根据约定规则计算href
		if (!options.href) {
			var pathname = location.pathname;
			var slash = pathname.lastIndexOf("/");
			var suffix = pathname.substring(Math.max(0, slash));
			var dot = suffix.lastIndexOf(".");
			options.href = path.href + (dot < 0 ? "/" : suffix.substring(dot));
		}

		var extras = {"Boolean":{map:{"true":"是","false":"否"},list:[{key:"true",value:"是"},{key:"false",value:"否"}]}};

		me.zoptions({ initial:options, extras:extras });
		var url = DEF.getBaseUrl(options.href.replace(/^\//, ""));
		me.zload({ 
			url:url, 
			bodyRule: [ /(<section[^<>]*class=['"][^"']*lyt-content[^'"]*["'][^<>]*>(.|[\r\n])*<\/section>)/im ],
			dataFilter: function(data) {
				// 检查用户是否登录
				var auth = DEF.checkAuthorized.call(this, data);
				if (typeof(auth) == "string") { return auth; }
				else if (auth === false) { return ""; }
				else { return $.zhh.format('{{}}', data, { initial:options }); }
			},
			success: function() {
				var space = $(this).children("section.lyt-content");
				$.zhh.events.trigger(space[0], options.space, space, options, extras);
			}
		});
	};
	// 新规则, 路径仅支持四级: 第一级(#号前)是模块名, 与页面的层级无关, 叫什么都可以; 后三级(#号后)定位到具体页面
	// /system/#/auth/personnel/account/ --> system/auth/personnel/account
	// 也支持静态页面的方式
	//  /system/index.html#/auth/personnel/account/ --> system/auth/personnel/account
	var hashToPath = function(space) {
		var view = space.replace(/:/g, "/").replace(/^\/|\/$/g, "");
		// shiro登录之后有可能会带JSESSIONID  http://localhost:8888/m/;JSESSIONID=xx
		var uri = window.location.href.replace(/([;?#].*)/, "");
		var m = /\/([\-\.\w]+)\/[\-\.\w]*$/.exec(uri);
		if (!m) {
			throw Error("Cann't open the tab page, path error: " + uri + "#" + space);
		}
		return { href:m[1] + view, module:m[1], view:view };
	};
	var viewToSpace = function(view) { 
		return "/" + view + "/";
	};
	// 处理路径中的.和..
	var formatPath = function(path) {
		var array = path.split(/[\/]+/);
		var paths = [];
		for (var i = 0; i < array.length; i++) {
			if (array[i] == ".") {
			} else if (array[i] == "..") {
				for (var j = paths.length - 1; j >= 0; j--) {
					if (paths[j] == undefined) { continue; }
					paths[j] = undefined;
					break;
				}
			} else {
				paths.push(array[i]);
			}
		}
		var buffer = "";
		for (var i = 0; i < paths.length; i++) {
			if (!paths[i]) { continue; }
			buffer += (buffer.length > 0 ? "/" : "") + paths[i];
		}
		return (path.startsWith("/") ? "/" : "") + buffer + (path.endsWith("/") ? "/" : "");
	};

	/**
	$("a").filterOptions("name", "save"); -- <a data-options="name:'save'"></a>
	$("a").filterOptions("url"); -- <a data-options="url:'http://...'"></a>
	**/
	$.fn.filterOptions = function(key, value) {
		var regexp;
		if (typeof(value) == "string") {
			regexp = new RegExp("['\"]?\\b"+key+"\\b[\"']?\\s*:\\s*['\"]"+value+"[\"']\\s*(,|$)", "m");
		} else if (typeof(value) == "boolean" || typeof(value) == "number") {
			regexp = new RegExp("['\"]?\\b"+key+"\\b[\"']?\\s*:\\s*"+value+"\\s*(,|$)", "m");
		} else if (value == null) {
			regexp = new RegExp("['\"]?\\b"+key+"\\b[\"']?\\s*:", "m");
		}
		return this.filter(function() {
			return regexp.test($(this).attr("data-options"));
		});
	};
	$.fn.xcall = function(operate, options) {
		var xcall = this.data("x-call");
		if (xcall) {
			if (this.data(DELAY)) { // 有延迟加载数据, 表示该元素还没有初始化
				DEF[xcall] && DEF[xcall].call(this[0]); // 先初始化
			}
			return this.eq(0)[xcall](operate, options);
		} else {
			$.log.error("data x-call not found.");
		}
	};
	/**
	space.xfind("xxx"); // find()的加强版
	// 由于dialog弹出后已经跳出原dom结构, 成为<body>的子元素了
	// find()方法就找不到dialog中的元素了, 但这个加强版能找到, 而且不会冲突
	**/
	$.fn.xfind = function(selector) {
		var list = this.find(selector);
		this.each(function() {
			var me = $(this);
			var popts = me.xcall("options");
			if (popts.popups) { // 已初始化的
				for (var type in popts.popups) {
					popts.popups[type].find(selector).each(function() {
						list.push(this);
					});
				}
			}
		});
		return list;
	};
	/**
	 * 刷新
	 * $(xxx).xreload(); // 刷新自已
	 * $(xxx).xreload(true); // 刷新子元素
	 * $(xxx).xreload(true, true); 刷新自己和子元素
	 * 有reload方法并且有url的元素才能刷新
	 * children:true/false, 是否刷新子元素
	 * self:true/false, 是否刷新自己
	 * @author zhaohuihua
	 */
	$.fn.xreload = function(children, self) {
		var me = this;
		var opts = me.xcall("options");
		if (opts.tabs && !opts.loadSuccess) {
			// 如果是tabs页签, 又加载失败了, 则重新加载整个页面
			me.xcall("refresh");
			return;
		}
		// 刷新子元素
		if (children) {
			$.each($.parser.plugins, function(i, key) {
				// 有reload方法并且有url的元素才能刷新
				if (!$.fn[key].methods.reload) { return true; }
				me.find(".x-" + key).filterOptions("url").each(function() {
					var me = $(this);
					me[key]("options").inited = false;
					me[key]("reload");
				});
			});
		}
		// 刷新自已
		if (self || children == undefined) {
			var key = this.data("x-call");
			if (key && $.fn[key].methods.reload) {
				this.filterOptions("url").each(function() {
					var me = $(this);
					me[key]("options").inited = false;
					me[key]("reload");
				});
			}
		}
	};
	// space.xpopups("type", "open", options);
	$.fn.xpopups = function(type, operate, options) {
		var popts = this.panel("options");
		if (!type) { // 查找全部对话框
			var list = [];
			if (popts.popups) { // 已初始化的
				for (var type in popts.popups) {
					$.each(popts.popups[type], function() { list.push(this); });
				}
			}
			this.find(".x-dialog, .x-window").each(function() {
				list.push(this);
			});
			return $(list);
		}
		if (popts.popups && popts.popups[type]) {
			// 对话框已初始化
			if (operate) {
				return popts.popups[type].dialog(operate, options);
			} else {
				return popts.popups[type];
			}
		} else {
			// 对话框未初始化
			var popup = this.find(".x-dialog, .x-window").filterOptions("xpopup", type);
			popup.each(function() {
				xpopup.call(this);
			});
			return popup;
		}
	};

	/*
	// 判断是不是全局变量
	// 为避免coder不执行规范, 不留太多余地, 未声明为全局变量的一律作为内部变量处理
	// 如果需要改变规则, 以全局变量优先, 则:
	$.fn.xui.defaults.globalVariables.push(function(name) {
		if ($.zhh.field(window, name)) { return true; }
	});
	*/
	var isGlobalVariable = function(name) {
		if (BASE.test(name)) { return true; }
		var gvs = DEF.globalVariables;
		for (var i = 0; i < gvs.length; i++) {
			var gv = gvs[i];
			var global = false;
			if (typeof(gv == "string")) { // 前缀
				global = name.startsWith(gv + ".");
			} else if (gv.test) { // 正则表达式
				global = gv.test(name);
			} else if ($.isFunction(gv)) { // 函数
				global = gv(name);
			}
			if (global) { return true; }
		}
		return false;
	};
	var handleOptions = function(prefix, variables) {
		var me = $(this);
		if (me.data("x-call")) {
			return;
		}
		// 从options中查找function声明, 追加前缀
		var attrs = [];
		var text = me.attr("data-options");
		for (var i = 0, matcher = null; text;) {
			matcher = VARS.exec(text);
			if (!matcher) {
				attrs.push(text.substring(i));
				break;
			}
			var index = matcher.index;
			var name = matcher[4];
			attrs.push(text.substring(i, index));
			attrs.push(matcher[1]);
			attrs.push(matcher[2]);
			attrs.push(matcher[3]);
			if (!isGlobalVariable(name)) { // 非全局变量
				attrs.push(prefix); // 追加前缀
				// 检查局部变量是否存在
				if (!$.zhh.field(variables, name)) { 
					$.log.error(name + " not found!");
				}
			}
			attrs.push(name);
			if (!isGlobalVariable(name)) { // 非全局变量
				// 用前缀为$的变量记录下原始函数名
				attrs.push(",");
				attrs.push(matcher[1]);
				attrs.push("$");
				attrs.push(matcher[2]);
				attrs.push(matcher[3]);
				attrs.push("'");
				attrs.push(name);
				attrs.push("'");
			}
			i = index + matcher[0].length;
		}
		var newer = attrs.join("");
		// if (text != newer) { $.log.debug(newer); }
		me.attr("data-options", newer);
	};

	// datalist : datagrid or treegrid ...
	// 根据当前选中行决定toolbar按钮的禁用/启用/隐藏/显示状态
	// 判断按钮状态, e = { datalist, selected, checked }
	var doButtonStateCheck = function(e, options) {
		var result;
		if ($.isFunction(options)) {
			// disableWith or enableWith or showWith or hideWith: function(e) { return e.selected.state == "NORMAL"; }
			result = options.call(this, e);
		} else {
			// disableWith or enableWith or showWith or hideWith: {state:"NORMAL",gender:["MALE","FEMALE"]}
			result = true;
			var list = e.checked || [e.selected];
			$.each(list, function() {
				for (var key in options) {
					var value = $.isArray(options[key]) ? options[key] : [ options[key] ];
					if ($.inArray(this[key], value) < 0) {
						result = false; break;
					}
				}
				if (!result) { return false; }
			});
		}
		return result;
	};
	var doButtonStateSwitch = function(e) {
		var me = $(this);
		var opts = me.linkbutton("options");
		if (opts.disableWith) {
			var result = doButtonStateCheck.call(this, e, opts.disableWith);
			me.linkbutton( result === true ? "disable" : "enable" );
		} else if (opts.enableWith) {
			var result = doButtonStateCheck.call(this, e, opts.enableWith);
			me.linkbutton( result === true ? "enable" : "disable" );
		} else {
			me.linkbutton( "enable" );
		}
		if (opts.hideWith) {
			var result = doButtonStateCheck.call(this, e, opts.hideWith);
			me[result === true ? "hide" : "show"]();
		} else if (opts.showWith) {
			var result = doButtonStateCheck.call(this, e, opts.showWith);
			me[result === true ? "show" : "hide"]();
		} else {
			me.show();
		}
	};
	// 当选择行数改变, e = { datalist, selections }
	var onDatalistSelectionsChanged = function(e) {
		var me = $(this);
		var buttons = me.xcall("getPanel").find(".datagrid-toolbar .x-linkbutton");
		var single = buttons.filterOptions("selection", "single");
		if (!e.selections.length) {
			single.linkbutton( "disable" );
		} else {
			var selected = e.selections[0];
			single.each(function() {
				var evt = $.extend({ selected:selected }, e, { selections:undefined });
				doButtonStateSwitch.call(this, evt);
			});
		}
	};
	// 当勾选行数改变, e = { datalist, checked }
	var onDatalistCheckedChanged = function(e) {
		var me = $(this);
		var buttons = me.xcall("getPanel").find(".datagrid-toolbar .x-linkbutton");
		var multi = buttons.filterOptions("selection", "multi");
		if (!e.checked.length) {
			multi.linkbutton( "disable" );
		} else {
			multi.each(function() {
				doButtonStateSwitch.call(this, $.extend({ }, e));
			});
		}
	};
	// 检查选中行数是否改变
	var checkDatalistSelections = function(e) {
		var me = $(this);
		var dopts = me.xcall("options");
		var selections = me.xcall("getSelections");
		if (dopts.counter.selections != selections.length) {
			dopts.counter.selections = selections.length;
			onDatalistSelectionsChanged.call(this, $.extend({selections:selections}, e));
		}
		var checked = me.xcall("getChecked");
		if (!checked.length) { checked = selections; }
		if (dopts.counter.checked != checked.length) {
			dopts.counter.checked = checked.length;
			onDatalistCheckedChanged.call(this, $.extend({checked:checked}, e));
		}
	};
	// 截获extra参数
	// datalist: xextra:true
	// datalist: xextra:{fields:['Gender',...], url:'extra.json',method:'GET',data:'extra'}
	// datalist: xextra:['Gender',{field:'areas',key:'areaCode',value:'areaName'},{xxx:onExtraChangedOfXxx,data:'extra.Xxx'}]
	// 'Gender'是简写, 相当于{'field':'Gender',key:'key',value:'value',data:'extra.Gender'}
	// combobox: xextra:'Gender',prepend:{key:'',value:'全部'}
	// combobox: xextra:'Gender',ignore:"UNKNOWN"
	// combobox: xextra:'Gender',ignore:[{key:"UNKNOWN"}]
	var filterExtraData = function(space, xe, data) {
		var self = this;
		var extras = space.xcall("options").extras;
		if (!xe) { return; }
		if (xe === true) { xe = {}; }
		else if ($.isArray(xe)) { xe = { fields:xe }; }

		var items = {};
		if (data) {
			var n = $.zhh.field(data, xe.data || "extra");
			if (n) {
				for (var key in n) { if (key) { items[key] = n[key]; } }
			}
		}
		if (xe.url && !xe.inited) {
			$.ajax({ url:xe.url, method:xe.method || "GET", async:false,
			success:function(data) {
				var n = $.zhh.field(data, xe.data || "extra");
				for (var key in n) { if (key) { items[key] = n[key]; } }
				xe.inited = true;
			}, error:function(e) {
				$.log.error(e);
			}});
		}
		var fields = {};
		$.each(xe.fields || [], function(i, item) {
			var list = [];
			if (typeof(item) == "string") {
				// 简写转换为完整格式
				// 'Gender' -- {'field':'Gender',config:{key:'key',value:'value'}}
				fields[item] = { field:item, config:{ key:"key", value:"value" } };
				if (!(item in items)) { items[item] = undefined; }
			} else if ("field" in item) {
				var config = $.extend({ key:"key", value:"value" }, item);
				fields[item.field] = { field:item.field, config:config };
				if (!(item.field in items)) { items[item.field] = undefined; }
			} else {
				for (var key in item) {
					if ($.isFunction(item[key])) {
						fields[key] = { field:key, fn:item[key] };
						if (!(key in items)) { items[key] = undefined; }
					}
				}
			}
		});

		if ($.isEmptyObject(items)) {
			return;
		}

		var map = {};
		// xextra:[{'AdminState':'State'}], key=AdminState, value=State
		for (var value in items) {
			// 如果没有特殊规则, 采用默认规则
			var opts = fields[value] || { field:value, config:{ key:"key", value:"value" } };
			var config = opts.config;
			var key = opts.field;

			var list = config && config.data ? $.zhh.field(data, config.data) : items[value];
			if (!$.isArray(list)) { continue; }
			var copy = [];
			$.each(list || [], function(i, o) { 
				copy.push($.extend({}, o));
			});
			if (opts.fn) { // 调用外部函数
				var temp = { map:{}, list:[], config:$.extend(true, {}, config) };
				var newvalue = opts.fn.call(self, temp, copy, data);
				if (newvalue !== false) {
					extras[key] = temp;
				}
			} else {
				extras[key] = { map:{}, list:[], config:$.extend(true, {}, config) };
				// 默认按枚举处理
				// 如: { extra: { Gender:[{key:"MALE",value:"男"},{key:"FEMALE",value:"女"}] }
				DEF.handleExtraData.call(self, extras[key], copy, data);
			}
			map[key] = extras[key];
		};
		initExtraInput.call(self, space, map);
	};
	
	var initExtraInput = function(space, map) {
		// 延迟加载关联的下拉框
		setTimeout(function() {
			for (k in map) {
				if (!k || !map[k].list || !map[k].map) { continue; }
				// 替换在当前extra数据加载之前就已经格式化了的数据
				// 例如左右两个datalist, 右侧某一列依赖左侧的extra.Gender
				// 由于加载速度不一样, 如果右侧先加载, 则格式化为占位符
				// 类似于<span data-extra-pending-Gender="MALE"></span>
				// 左侧加载完成后再把占位符替换为真正显示的内容(男)
				space.find("[data-extra-pending-" + k + "]").each(function() {
					var me = $(this);
					var value = me.attr("data-extra-pending-" + k);
					me.text(map[k].map[value]).removeAttr("data-extra-pending-" + k);
				});
				// 查找关联的下拉框, 填充数据
				space.xfind("input").filterOptions("xextra", k).each(function() {
					var me = $(this);
					var opts = me.xcall("options");
					var key = me.attr("textboxname");
					if (typeof (opts.xextra) == "string") {
						key = opts.xextra;
					}
					var attr = $.parser.parseOptions(this);
					var config = map[key].config || { key:"key", value:"value" };
					var xcall = $(this).data("x-call");
					// 没有loadData方法, continue
					if (!$.fn[xcall].methods.loadData) { return true; }
					if (xcall == "tree" || xcall == "treegrid" || xcall == "combotree") {
						if (!attr.idField) { opts.idField = config.key; }
						if (!attr.treeField) { opts.treeField = config.value; }
						if (!attr.parentField) { opts.parentField = config.parent; }
					} else {
						if (!attr.valueField) { opts.valueField = config.key; }
						if (!attr.textField) { opts.textField = config.value; }
						if (!attr.groupField) { opts.groupField = config.group; }
					}
					var values = [];
					// 有可能需求增加"全部","请选择"之类
					if (opts.prepend) { values.push($.extend({}, opts.prepend)); }
					// 复制节点
					$.each(map[key].list, function(i, item){
						var valid = true;
						if (opts.ignore) { // 判断是不是有效
							var ignore = $.isArray(opts.ignore) ? opts.ignore : [opts.ignore];
							$.each(ignore, function(i, n) {
								if (typeof(n) == "string") {
									if (item[config.key] == n) {
										valid = false; return false;
									}
								} else {
									var matched = true;
									for (var key in n) {
										if (n[key] != item[key]) { matched = false; }
									}
									if (matched) { valid = false; return false; }
								}
							});
						}
						// 复制节点
						if (valid) { values.push($.extend(true, {}, item)); }
					});
					if (opts.append) { values.push(opts.append); }
					// 填充数据
					me.xcall("loadData", values);
				});
			}
		}, 100);
	};
	var callEvent = function(event, serial, args) {
		var opts = $(this).xcall("options");
		var xcall = $(this).data("x-call");
		var name = opts["$" + event];
		if (name && xui[serial][name]) {
			// 调用业务代码(data-options="xxx:fn")
			return xui[serial][name].apply(this, args);
		} else {
			// 调用默认实现
			return $.fn[xcall].defaults[event].apply(this, args);
		}
	};
	var xdatalist = function(options) {
		var me = $(this);
		var params = {
			loadMsg:"", xref:{space:options.space}, counter:{ selections:0, checked:0 },
			singleSelect:true, checkOnSelect:true, selectOnCheck:false
		};
		var serial = options.serial;
		var space = options.space;
		if (space.length) {
			var opts = $.parser.parseOptions(this);
			$.each(["toolbar", "footer"], function(i, key) {
				if (typeof(opts[key]) == "string") {
					var node = space.find(opts[key]);
					if (node.length) { params[key] = node; }
				}
			});

			// 从<th>查找checkbox:true的作为idField
			if (!opts.idField) {
				var checkbox = me.find("thead th").filterOptions("checkbox", true);
				if (checkbox.length) {
					params.idField = $.parser.parseOptions(checkbox[0]).field;
				}
			}

			// 重写loadFilter事件, 植入代码用于截获extra参数
			params.loadFilter = function(data) {
				if (data) {
					var xextra = $(this).xcall("options").xextra;
					if (xextra) {
						// 调用植入代码
						filterExtraData.call(this, space, xextra, data);
					}
				}
				// 调用业务代码
				return callEvent.call(this, "loadFilter", serial, arguments);
			};
			// 重写onBeforeLoad事件, 植入代码用于通过form获取查询参数
			// datagrid.onBeforeLoad(param), treegrid.onBeforeLoad(row, params), tree.onBeforeLoad(node, params)
			params.onBeforeLoad = function(dp, tp) {
				var opts = $(this).xcall("options");
				var params = tp || dp; // datagrid,treegrid的params位置不一样
				if (!opts.inited) { params.extra = true; if (opts.url) { opts.inited = true; } }
				params.paging = opts.pagination; // 是否分页
				params.needCount = opts.pagination; // 是否需要统计总数
				var initial = opts.xref.space.xcall("options").initial;
				// fixedParams是每次请求都会追加的参数
				// 与queryParams的区别是, dg.datagrid("load",{}), queryParams会被清除, fixedParams清除不掉
				$.extend(params, initial.fixedParams, opts.fixedParams);
				var form = $(this).xcall("getPanel").find(".datagrid-toolbar form");
				if (form.length) { $.extend(params, form.serializeJson()); }
				// 调用业务代码
				return callEvent.call(this, "onBeforeLoad", serial, arguments);
			};
		}
		// 绑定一堆事件, 植入一段代码, 用于检查选中行数是否改变
		var events = "onLoadSuccess onCheck onUncheck onCheckAll onUncheckAll onSelect onUnselect onSelectAll onUnselectAll";
		$.each(events.split(/\s+/), function(i, event) {
			params[event] = function() {
				checkDatalistSelections.call(this, {datalist:me}); // 调用植入代码
				return callEvent.call(this, event, serial, arguments); // 调用业务代码
			};
		});
		me.xcall(params);

		var dopts = me.xcall("options");
		dopts.xref.space = space;

		me.xcall("getPanel").find(".datagrid-toolbar .x-linkbutton").each(function() {
			// 将button与datagrid关联起来
			var btn = $(this);
			var bopts = btn.linkbutton("options");
			bopts.xref.space = space;
			bopts.xref.datalist = me;
			bopts.xref.toolbar = btn.closest("datagrid-toolbar");
			bopts.xref.form = btn.closest("form");
			if (bopts.selection == "single" || bopts.selection == "multi") {
				btn.linkbutton("disable");
			}
			if (bopts.showWith || bopts.hideWith) {
				btn.hide();
			}

			// 根据xaction设定默认的行为, xpopup=打开对话框
			var type = bopts.xpopup ? "popup" : bopts.xaction;
			if (type) {
				if (DEF.onToolbarButton[type]) {
					// 绑定点击事件
					bopts.onClick = DEF.onToolbarButton[type].onClick;
					for (var key in DEF.onToolbarButton[type]) {
						if (bopts[key] === undefined || bopts[key] == $.fn.linkbutton.defaults[key]) {
							bopts[key] = DEF.onToolbarButton[type][key];
						}
					}
				} else {
					$.log.error("$.fn.xui.defaults.onToolbarButton[" + type + "] not found");
				}
			}
		});
	};
	// now:true  默认设置为当前时间
	// ignoreYear:true  月日格式
	// startTime:true  时间部分设置为00:00:00
	// endTime:true  时间部分设置为23:59:59
	var xdatetime = function(options) {
		var me = $(this);
		var serial = options.serial;
		var params = { xref:{space:options.space} };
		var opts = $.parser.parseOptions(this);
		if (opts.now) { params.value = Dates.format(new Date()); }
		params.onShowPanel = function() {
			var pnl = me.xcall("panel");
			var opts = me.xcall("options");
			var years = pnl.find(".calendar-prevyear, .calendar-nextyear, .calendar-menu-year-inner");
			var title = pnl.find(".calendar-title .calendar-text");
			var calendar = me.xcall("calendar").data("calendar").options;
			if (opts.ignoreYear) {
				years.hide();
				title.text(calendar.months[calendar.month - 1]);
			} else {
				years.show();
				title.text(calendar.months[calendar.month - 1] + " " + calendar.year);
			}
			// 调用业务代码
			return callEvent.call(this, "onShowPanel", serial, arguments);
		};
		if (opts.ignoreYear) { // 月日格式
			params.formatter = function(date) {
				if (typeof(date) == "string") {
					date = Dates.parse(date, new Date());
				}
				return Dates.format(date, "MM月dd日");
			};
			params.parser = function(date){
				return Dates.parse(date, new Date());
			};
		} 
		if (opts.ignoreYear || opts.startTime || opts.endTime) {
			params.onChange = function(newvalue, oldvalue) {
				var date = Dates.parse(newvalue);
				if (date && !isNaN(date)) {
					if (opts.ignoreYear) {
						date.setFullYear(2000);
					}
					if (opts.endTime) {
						date.setHours(23);
						date.setMinutes(59);
						date.setSeconds(59);
						date.setMilliseconds(999);
					} else if (opts.startTime) {
						date.setHours(0);
						date.setMinutes(0);
						date.setSeconds(0);
						date.setMilliseconds(0);
					}
					$(this).xcall("textbox").parent().find(".textbox-value").val(Dates.format(date));
				}
				// 调用业务代码
				return callEvent.call(this, "onChange", serial, arguments);
			};
		}
		me.xcall(params);
	};
	var xtextbox = function(options) {
		var me = $(this);
		var params = { xref:{space:options.space} };
		var opts = $.parser.parseOptions(this);
		if (opts.pinyin) {
			var serial = options.serial;
			params.onChange = function(value) {
				// 处理拼音
				if (value) {
					$.post(opts.pinyin.url, {text:value}, function(json) {
						$.each(["short", "full", "mark"], function(i, type) {
							if (opts.pinyin[type]) {
								me.closest("form").find(opts.pinyin[type]).xcall("setValue", json.body[type]);
							}
						});
					});
				} else {
					$.each(["short", "full", "mark"], function(i, type) {
						if (opts.pinyin[type]) {
							me.closest("form").find(opts.pinyin[type]).xcall("setValue", "");
						}
					});
				}
				return callEvent.call(this, "onChange", serial, arguments); // 调用业务代码
			};
		}
		me.xcall(params);
	};
	var xpopup = function(options) {
		var me = $(this);
		if (options && options.init === true) {
			// 延迟加载
			me.data(DELAY, options);
			return;
		}

		if (me.data(DELAY)) {
			options = me.data(DELAY);
			me.removeData(DELAY);
		}

		var serial = options.serial;
		var space = options.space;
		var params = { xref:{space:space} };
		// 重写onOpen事件, 植入代码用于initValidation的判断
		params.onOpen = function() {
			var opts = $(this).xcall("options");
			if (opts.xref.form && opts.initValidation != "enabled") {
				opts.xref.form.form("disableValidation");
			}
			// 调用业务代码
			return callEvent.call(this, "onOpen", serial, arguments);
		};
		me[options.type](params);

		var dopts = me[options.type]("options");
		var form = me.find("form");
		if (form.length) {
			dopts.xref.form = form;
		}

		// 将对话框绑定到space上
		// 以便通过space.xpopups(xxx)引用, 和当space销毁时销毁对话框
		var type = dopts.xpopup;
		if (type && space.length) {
			var popts = space.panel("options");
			if (!popts.popups) { popts.popups = {}; }
			popts.popups[type] = me;
		}

		// me.dialog("dialog")  or  me.window("window")
		me[options.type](options.type).find(".x-linkbutton").each(function() {
			// 将button与dialog关联起来
			var btn = $(this);
			// 对话框中datagrid
			if (btn.closest(".datagrid-toolbar").length) { return; }
			var bopts = btn.linkbutton("options");
			bopts.xref.space = space;
			bopts.xref.popup = me;
			if (form.length > 0) { bopts.xref.form = form; }

			// 根据xaction设定默认的行为
			var type = bopts.xpopup ? "popup" : bopts.xaction;
			if (type) {
				if (DEF.onPopupButton[type]) {
					// 绑定点击事件
					bopts.onClick = DEF.onPopupButton[type].onClick;
					for (var key in DEF.onPopupButton[type]) {
						if (bopts[key] === undefined || bopts[key] == $.fn.linkbutton.defaults[key]) {
							bopts[key] = DEF.onPopupButton[type][key];
						}
					}
				} else {
					$.log.error("$.fn.xui.defaults.onPopupButton[" + type + "] not found");
				}
			}
		});
	};

	var DEF = $.fn.xui.defaults = {
		filterExtraData:filterExtraData,
		// globalVariables: string | RegExp | Function
		globalVariables: ["window", "xui"],
		checkAuthorized: function(data) { }, // 检查用户是否登录
		getBaseUrl: function(url) { return url; },
		// 处理附加数据的默认函数
		// e = { list:[], map:{}, config:{ key:"key", value:"value", parent:"parent" } }
		// data = [{key:"MALE",value:"男"},{key:"FEMALE",value:"女"}]
		handleExtraData: function(e, extra, data) {
			e.list = extra;
			var key = e.config.key;
			var value = e.config.value;
			$.each(extra, function() {
				this[key] && (e.map[this[key]] = this[value]);
			});
		},
		datagrid:xdatalist,
		treegrid:xdatalist,
		dialog:xpopup,
		window:xpopup,
		textbox:xtextbox,
		datebox:xdatetime,
		datetimebox:xdatetime,
		isJsonSuccess: function(json) {
			return json && json.code == "SUCCESS";
		},
		onToolbarButton: { // 点击工具栏的按钮
			reset: { // 重置搜索条件
				onClick:function() {
					var btn = $(this);
					var bopts = btn.xcall("options");
					bopts.xref.form.form("clear");
					bopts.xref.datalist.xcall("load", {});
				}
			},
			search: { // 提交搜索条件
				onClick:function() {
					var btn = $(this);
					var bopts = btn.xcall("options");
					var form = bopts.xref.form;
					form.form("enableValidation");
					if (form.form("validate")) {
						// 通过onBeforeLoad提交参数
						// var params = form.serializeJson();
						// bopts.xref.datalist.xcall("load", params);
						bopts.xref.datalist.xcall("load");
					}
				}
			},
			// data-options="xpopup:'details'"  打开'详情'对话框
			// data-options="xpopup:'create',fillData:false"  打开'创建'对话框, 不要加载数据
			// data-options="xpopup:'delete',fillData:false,onAfterFillData:onAfterFillDataOfXxx"
			//	 打开'删除'对话框并由具体业务层处理表单填充
			// data-options="xaction:'xxx'"  执行$.fn.xui.defaults.onToolbarButton.xxx, 用于扩展
			popup: { // 弹出对话框
				onClick:function() {
					var btn = $(this);
					var bopts = btn.xcall("options");
					var e = doPopupFindSelections.call(this);
					var result = bopts.onBeforeOpen.call(this, $.extend({}, e));
					if (result === false) { return; }

					// 查找对话框
					var popup = bopts.xref.space.xpopups(bopts.xpopup);
					var popts = popup.xcall("options");

					// 传递参数
					bopts.xref.popup = popup;
					popts.xref.launcher = btn;
					if (bopts.xref.datalist) {
						popts.xref.datalist = bopts.xref.datalist;
					}

					e.popup = popup; e.space = popts.xref.space; e.form = popts.xref.form;

					doPopupFillData.call(this, $.extend({}, e));

					// 控制按钮的禁用/启用/隐藏/显示
					var buttons = popup.xcall("window").find(".dialog-button a.x-linkbutton");
					var de = buttons.filterOptions("disableWith").add(buttons.filterOptions("enableWith"));
					var hs = buttons.filterOptions("hideWith").add(buttons.filterOptions("showWith"));
					if (!e.selected) {
						de.linkbutton( "disable" );
						hs.hide();
					} else {
						de.add(hs).each(function() {
							doButtonStateSwitch.call(this, { selected:e.selected });
						});
					}

					popup.xcall("open").xcall("center");

					bopts.onAfterOpen.call(this, $.extend({}, e));
				},
				onBeforeOpen: function(e) { // 打开对话框之前的事件
					// 这里的e只有datalist, 没有对话框相关的引用, 因为对话框可能还没有初始化
				},
				onBeforeFillData: function(e) { // 填充数据之前的事件
				},
				onAfterFillData: function(e) { // 点击按钮打开对话框时的事件
				},
				onAfterOpen: function(e) {
				},
				// 打开对话框时是否立即启动校验, 默认='disabled', 表示打开时不校验, 提交时再启动校验, 体验较好
				initValidation:"disabled",
				// 打开对话框时是否加载选中行数据
				fillData:true,
				// 打开对话框时是否清空form
				clearOnOpen:true,
				// 允许选择几行, 默认:不控制,单行:single,多行:multi
				selection:undefined,
				// 根据当前选中行决定toolbar按钮的禁用/启用/隐藏/显示状态
				enableWith:undefined,
				disableWith:undefined,
				showWith:undefined,
				hideWith:undefined
			}
		},
		onPopupButton: { // 点击对话框的按钮
			close: { // 关闭
				onClick: function() {
					var btn = $(this);
					var bopts = btn.xcall("options");
					var popup = bopts.xref.popup;
					popup.xcall("close");
				}
			},
			prev: { // 加载上一行
				onClick: function() {
					doDatalistNextPrev.call(this, -1);
				}
			},
			next: { // 加载下一行
				onClick: function() {
					doDatalistNextPrev.call(this, +1);
				}
			},
			submit: { // 提交
				onClick: function() {
					var btn = $(this);
					var bopts = btn.xcall("options");
					var popup = bopts.xref.popup;
					var form = bopts.xref.form;
					var space = bopts.xref.space;

					var popts = popup.xcall("options");
					var datalist = popts.xref.datalist;
					var e = { space:space, form:form, popup:popup, datalist:datalist };
					if (datalist) {
						e.selected = datalist.xcall("getSelected");
						e.checked = datalist.xcall("getChecked");
					}
					bopts.onReady.call(this, e, doSubmitExec);

					return false;
				},
				onReady: function(e, doSubmit) { // 准备提交, 用于插件扩展
					doSubmit.call(this, e);
				},
				onBefore: function(e) { // 表单提交前事件, 用于具体业务, 返回false将终止表单提交
					return true;
				},
				dataFilter: function(e) { // 解析响应数据, 用于基础业务和插件扩展
					return e.data;
				},
				isSuccess: function(e) { // 判断提交是否成功, 用于基础业务和插件扩展
					return DEF.isJsonSuccess.call(this, e.data);
				},
				onFinish: function(e, doFinish) { // 提交完成, 用于插件扩展
					doFinish.call(this, e);
				},
				onSuccess: function(e) { // 提交成功的事件, 用于具体业务, return false可以取消默认的通知事件
				},
				onError: function(e) { // 提交失败的事件, 用于具体业务, return false可以取消默认的通知事件
				},
				onMessage: function(e) { // 通知事件, 用于基础业务和插件扩展
					if (!e.success && e.xhr) {
						$.log.error(e);
					}
				},
				closeOnSuccess:true, // 提交成功后是否关闭对话框
				clearOnSuccess:false, // 提交成功后是否清空表单
				reloadOnSuccess:true, // 提交成功后是否重新加载列表
				closeOnError:false, // 提交失败后是否关闭对话框
				clearOnError:false, // 提交失败后是否清空表单
				reloadOnError:false, // 提交失败后是否重新加载列表
				validate:true, // 提交前是否需要验证
				message:undefined
			}
		}
	};

	var doDatalistNextPrev = function(to) {
		var btn = $(this);
		var bopts = btn.xcall("options");
		var popup = bopts.xref.popup;
		var popts = popup.xcall("options");
		var datalist = popts.xref.datalist;
		// 获取所有行
		var rows = datalist.xcall("getRows");
		if (rows && rows.length > 1) {
			// 获取选中行
			var selected = datalist.xcall("getSelected");
			var index = 0;
			if (selected) {
				// 获取当前序号
				var curr = datalist.xcall("getRowIndex", selected);
				// 计算新的序号
				index = curr + to;
				if (index < 0) { index = rows.length - 1; }
				else if (index >= rows.length) { index = 0; }
			}
			// 选中新的数据行
			datalist.xcall("unselectAll").xcall("selectRow", index);
			var launcher = popts.xref.launcher.get(0);
			var e = doPopupFindSelections.call(launcher);
			e.popup = popup; e.form = popts.xref.form;
			// 加载新数据
			doPopupFillData.call(launcher, e);
		}
	};
	var doPopupFindSelections = function() {
		var btn = $(this);
		var bopts = btn.xcall("options");
		var e = { };
		var datalist = bopts.xref.datalist;
		if (datalist) {
			e.datalist = datalist;
			e.selected = datalist.xcall("getSelected");
			e.checked = datalist.xcall("getChecked");
			if (e.selected && !e.checked.length) { e.checked = [ e.selected ]; }
		}
		return e;
	};
	var doPopupFillData = function(e) {
		var btn = $(this);
		var bopts = btn.xcall("options");
		var popup = e.popup;
		var popts = popup.xcall("options");
		var form = e.form;
		var initial = e.space.xcall("options").initial;
		bopts.onBeforeFillData.call(this, $.extend({}, e));

		if (form) {
			if (bopts.clearOnOpen) {
				form.form("clear");
			}
			// 填充initial.fixedParams固定参数
			var tpl = '<input type="hidden" name="{0}" value = "{1}"/>';
			if (initial.fixedParams) {
				var html = [];
				for (key in initial.fixedParams) {
					form.find("input[name='" + key + "']").remove();
					html.push($.zhh.format(tpl, key, initial.fixedParams[key]));
				}
				form.append(html.join(""));
			}
			// 判断是否需要填充数据
			var fillData = bopts.fillData;
			// 填充选中行数据
			if (e.selected && fillData === true) {
				form.form("load", $.extend({}, e.selected));
			}
			// 自定义的fillData, selection=multi会自动创建多个input[hidden]
			var checked = undefined;
			if (bopts.selection == "multi") {
				if (e.checked && e.checked.length) { checked = e.checked; }
			} else {
				if (e.selected) { checked = [e.selected]; }
			}
			if (typeof(fillData) == "string" || $.isPlainObject(fillData) || $.isArray(fillData)) {
				var batch = $.isArray(fillData) ? fillData : [fillData];
				$.each(batch, function(i, item) {
					var opts = toOptions(item);
					for (key in opts) {
						if (key != "i") { form.find("input[name='" + opts[key] + "']").remove(); }
					}
					if (!checked) { return true; }
					var html = [];
					$.each(checked, function(){
						for (key in opts) {
							if (key == "i") {
								form.find(opts[key]).text(checked.length);
							} else if (this[key]) {
								html.push($.zhh.format(tpl, opts[key], this[key]));
							}
						}
					});
					form.append(html.join(""));
				});
			}
		}
		bopts.onAfterFillData.call(this, $.extend({}, e));
	};


	var doSubmitExec = function(e) {
		var self = this;
		var btn = $(this);
		var form = e.form;
		var bopts = btn.linkbutton("options");
		if (bopts.validate !== false) {
			form.form("enableValidation");
		}
		var msg = bopts.message || $.trim(btn.text());

		// 提交前禁用按钮
		btn.linkbutton("disable");
		form.form("submit", {
			onSubmit: function() {
				// 验证表单
				var valid = e.form.form("validate");
				// 触发表单提交前事件
				if (valid) { valid = bopts.onBefore.call(self, $.extend({}, e)); }
				// 如果验证未通过, 启用按钮
				if (valid === false) { btn.linkbutton("enable"); }
				return valid; // 返回false终止表单提交
			},
			success: function(data) {
				btn.linkbutton("enable");
				var evt = $.extend({data:data}, e);
				// 解析数据
				evt.data = bopts.dataFilter.call(self, evt);
				// 判断是否成功
				evt.success = bopts.isSuccess.call(self, evt) !== false;
				evt.message = msg;
				evt.suffix = true;
				bopts.onFinish.call(self, evt, doSubmitFinally);
			},
			onLoadError: function(xhr, status, thrown) {
				btn.linkbutton("enable");
				var evt = $.extend({ success:false, message:msg, suffix:true, xhr:xhr, status:status, thrown:thrown}, e);
				bopts.onFinish.call(self, evt, doSubmitFinally);
			}
		});
	};
	var doSubmitFinally = function(e) {
		var btn = $(this);
		var bopts = btn.xcall("options");
		var type = e.success ? "Success" : "Error";
		// 关闭对话框
		var close = bopts["closeOn" + type];
		if (close && e.popup) {
			e.popup.xcall("close");
		}
		// 清空表单
		var clear = bopts["clearOn" + type];
		if (clear && e.form) {
			e.form.form("clear").form("disableValidation");
			var popts = e.form.form("options");
			if (popts.initValidation != "enabled") {
				e.form.form("disableValidation");
			}
		}
		// 重新加载列表
		var reload = bopts["reloadOn" + type];
		if (reload && e.datalist) {
			e.datalist.xcall("reload");
		}
		// 通知和最终回调
		var result;
		if (e.success) {
			result = bopts.onSuccess.call(this, e);
		} else {
			result = bopts.onError.call(this, e);
		}
		// return false可以取消默认的通知事件, return string可以替换默认的通知内容
		if (result !== false) {
			if (typeof(result) == "string") {
				e.message = result;
				e.suffix = false;
			}
			bopts.onMessage.call(this, e);
		}
	};



}(jQuery);



